#include <cppscript>
#include <dynamic/python.hpp>

void test_py_int(var interp)
{
	var python_int = interp["create_int"];
	assertx( python_int(123).as_int() == 123 );
	assertx( python_int(2).as_double() == 2.0 );
	assertx( python_int(2).as_string() == "2" );
}

void test_py_eval(var interp)
{
	var python_eval = interp["eval"];
	assertx( python_eval("2+3").as_int() == 5 );
	assertx( python_eval("'abc'").as_string() == "abc" );

	assertx( interp["eval_env"]("a", map("a",12)("b",2), map("a",4)).as_int() == 4 );

	var result = interp["eval_env"]("a", map("a",12)("b",2), map("x",4));
	// writeln(result);
	// assertx( result.as_int() == 12 );	// Fails because the map always succeeds
}

void test_py_double(var interp)
{
	var python_double = interp["create_double"];
	assertx( python_double(2.0).as_double() == 2.0 );
	assertx( python_double(1.0).as_int() == 1 );
	assertx( python_double(3.0).as_string() == "3.0" );
}

void test_py_bool(var interp)
{
	var python_bool = interp["create_bool"];
	assertx( python_bool(true) );
	assertx( !python_bool(false) );
}

void test_py_string(var interp)
{
	var python_string = interp["create_string"];
	assertx( python_string("abc").as_string() == "abc" );

	// !! wide strings
}

void test_python_to_var(var interp)
{
}

var add_fn(var a, var b) { return a+b; }

var throws() { throw exception("abc", "Hello"); }

void test_var_to_python(var interp)
{
	var eval_env = interp["eval_env"];

	// Test functions
	assertx( eval_env("add(2,3)", null, map("add", add_fn) ).as_int() == 5 );
	assertx( eval_env("add5(4)", null, map("add5", bind(add_fn, 5)) ).as_int() == 9 );
	assertx( eval_env("twelve()", null, map("twelve", bind(add_fn, 6,6))).as_int() == 12 );
	// !! Test more arguments

	// Test throws
	try
	{
		eval_env("throws()", null, map("throws", throws));
		assertx(0);
	}
	catch(var v)
	{
		assertx(v.class_name() == "abc");
		assertx(v["text"] == "Hello");
	}
}

void test_multiple_interpreters()
{
	var interp1 = python_interpreter();
	var interp2 = python_interpreter();
}

void test_threading()
{
}

void test_exceptions()
{
}

void test_py_eval_file(var interp)
{
	try
	{
		writeln( interp["eval_source_env"](
			//"12\n"
			//"13\n"
			"import sys\n"
			"dir('sys')\n"
			// "print 'Hello'\n"
			, map()) );
	}
	catch( var ex )
	{
		writeln( "Failed: " + ex );
	}
}

var script_main(var args)
{
	var interp = python_interpreter();

	return run_tests( map
			("int", bind(test_py_int, interp) )
			("eval", bind(test_py_eval, interp)) 
			("double", bind(test_py_double, interp))
			("bool", bind(test_py_bool, interp))
			("string", bind(test_py_string, interp))
			("python_to_var", bind(test_python_to_var, interp))
			("var_to_python", bind(test_var_to_python, interp))
			("multiple_interpreters", test_multiple_interpreters)
			("threading", test_threading)
			("exceptions", test_exceptions)
			("eval_file", bind(test_py_eval_file, interp))
		);
}
